package handler

import (
	"Data-API-MCP/backend/internal/domain/entity"
	"Data-API-MCP/backend/internal/domain/repository"
	"Data-API-MCP/backend/internal/domain/service"
	"Data-API-MCP/backend/internal/infrastructure/persistence"
	"Data-API-MCP/backend/internal/interfaces/http/response"
	"strconv"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// DBHandler 数据库处理器
type DBHandler struct {
	dbService service.DBService
	dbPool    *persistence.DBPool
	auditRepo repository.AuditRepository
	logger    *zap.Logger
}

// NewDBHandler 创建数据库处理器
func NewDBHandler(dbService service.DBService, dbPool *persistence.DBPool, auditRepo repository.AuditRepository, logger *zap.Logger) *DBHandler {
	return &DBHandler{
		dbService: dbService,
		dbPool:    dbPool,
		auditRepo: auditRepo,
		logger:    logger,
	}
}

// CreateConnection godoc
// @Summary 创建数据库连接
// @Description 创建新的数据库连接
// @Tags 数据库连接
// @Accept json
// @Produce json
// @Param connection body entity.DBConnection true "数据库连接信息"
// @Success 201 {object} entity.DBConnection
// @Failure 400 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections [post]
func (h *DBHandler) CreateConnection(c *gin.Context) {
	var conn entity.DBConnection
	if err := c.ShouldBindJSON(&conn); err != nil {
		h.logger.Error("无效的请求参数", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 加密密码
	encryptedPassword, err := persistence.EncryptPassword(conn.Password)
	if err != nil {
		h.logger.Error("密码加密失败", zap.Error(err))
		response.Error(c, err)
		return
	}
	conn.Password = encryptedPassword

	if err := h.dbService.CreateConnection(c.Request.Context(), &conn); err != nil {
		h.logger.Error("创建数据库连接失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "create",
		Resource:    "database",
		ResourceID:  conn.ID,
		Description: "创建数据库连接",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, conn)
}

// GetConnections godoc
// @Summary 获取数据库连接列表
// @Description 获取所有数据库连接
// @Tags 数据库连接
// @Produce json
// @Success 200 {array} entity.DBConnection
// @Failure 500 {object} errors.Error
// @Router /connections [get]
func (h *DBHandler) GetConnections(c *gin.Context) {
	// 请求入参是JSON格式
	var req struct {
		Page     int    `json:"page"`
		PageSize int    `json:"pageSize"`
		Keyword  string `json:"keyword"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		h.logger.Error("无效的请求参数", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 获取数据库连接列表
	conns, total, err := h.dbService.GetConnections(c.Request.Context(), req.Page, req.PageSize, req.Keyword)
	if err != nil {
		h.logger.Error("获取数据库连接列表失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 构建分页响应
	result := gin.H{
		"list":  conns,
		"total": total,
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "read",
		Resource:    "database",
		ResourceID:  0,
		Description: "获取数据库连接列表",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)
	response.Success(c, result)
}

// GetConnection godoc
// @Summary 获取单个数据库连接
// @Description 根据ID获取数据库连接
// @Tags 数据库连接
// @Produce json
// @Param id path int true "连接ID"
// @Success 200 {object} entity.DBConnection
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id} [get]
func (h *DBHandler) GetConnection(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	conn, err := h.dbService.GetConnection(c.Request.Context(), id)
	if err != nil {
		h.logger.Error("获取数据库连接失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "read",
		Resource:    "database",
		ResourceID:  id,
		Description: "获取数据库连接",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, conn)
}

// UpdateConnection godoc
// @Summary 更新数据库连接
// @Description 更新指定ID的数据库连接
// @Tags 数据库连接
// @Accept json
// @Produce json
// @Param id path int true "连接ID"
// @Param connection body entity.DBConnection true "数据库连接信息"
// @Success 200 {object} entity.DBConnection
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id} [put]
func (h *DBHandler) UpdateConnection(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	var conn entity.DBConnection
	if err := c.ShouldBindJSON(&conn); err != nil {
		h.logger.Error("无效的请求参数", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 如果密码不为空，则加密
	if conn.Password != "" {
		encryptedPassword, err := persistence.EncryptPassword(conn.Password)
		if err != nil {
			h.logger.Error("密码加密失败", zap.Error(err))
			response.Error(c, err)
			return
		}
		conn.Password = encryptedPassword
	}

	conn.ID = id
	if err := h.dbService.UpdateConnection(c.Request.Context(), &conn); err != nil {
		h.logger.Error("更新数据库连接失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "update",
		Resource:    "database",
		ResourceID:  id,
		Description: "更新数据库连接",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, conn)
}

// DeleteConnection godoc
// @Summary 删除数据库连接
// @Description 删除指定ID的数据库连接
// @Tags 数据库连接
// @Produce json
// @Param id path int true "连接ID"
// @Success 200 {object} map[string]string
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id} [delete]
func (h *DBHandler) DeleteConnection(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	if err := h.dbService.DeleteConnection(c.Request.Context(), id); err != nil {
		h.logger.Error("删除数据库连接失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 关闭连接池中的连接
	h.dbPool.CloseDB(id)

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "delete",
		Resource:    "database",
		ResourceID:  id,
		Description: "删除数据库连接",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, gin.H{"message": "连接已删除"})
}

// TestConnection godoc
// @Summary 测试数据库连接
// @Description 测试数据库连接是否可用
// @Tags 数据库连接
// @Accept json
// @Produce json
// @Param connection body entity.DBConnection true "数据库连接信息"
// @Success 200 {object} map[string]string
// @Failure 400 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/test [post]
func (h *DBHandler) TestConnection(c *gin.Context) {
	var conn entity.DBConnection
	if err := c.ShouldBindJSON(&conn); err != nil {
		h.logger.Error("无效的请求参数", zap.Error(err))
		response.Error(c, err)
		return
	}

	if err := h.dbService.TestConnection(c.Request.Context(), &conn); err != nil {
		h.logger.Error("测试数据库连接失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "execute",
		Resource:    "database",
		ResourceID:  0,
		Description: "测试数据库连接",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, gin.H{"message": "连接成功"})
}

// GetTables godoc
// @Summary 获取表列表
// @Description 获取指定数据库的所有表
// @Tags 数据库操作
// @Produce json
// @Param id path int true "连接ID"
// @Success 200 {array} entity.TableInfo
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id}/tables [get]
func (h *DBHandler) GetTables(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	tables, err := h.dbService.GetTables(c.Request.Context(), id)
	if err != nil {
		h.logger.Error("获取表列表失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "read",
		Resource:    "table",
		ResourceID:  id,
		Description: "获取表列表",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, tables)
}

// GetTableInfo godoc
// @Summary 获取表信息
// @Description 获取指定表的详细信息
// @Tags 数据库操作
// @Produce json
// @Param id path int true "连接ID"
// @Param table path string true "表名"
// @Success 200 {object} entity.TableInfo
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id}/tables/{table} [get]
func (h *DBHandler) GetTableInfo(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	tableName := c.Param("table")
	if tableName == "" {
		h.logger.Error("无效的表名", zap.Error(err))
		response.Error(c, err)
		return
	}

	info, err := h.dbService.GetTableInfo(c.Request.Context(), id, tableName)
	if err != nil {
		h.logger.Error("获取表信息失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "read",
		Resource:    "table",
		ResourceID:  id,
		Description: "获取表信息",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, info)
}

// GetColumns godoc
// @Summary 获取列信息
// @Description 获取指定表的所有列信息
// @Tags 数据库操作
// @Produce json
// @Param id path int true "连接ID"
// @Param table path string true "表名"
// @Success 200 {array} entity.ColumnInfo
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id}/tables/{table}/columns [get]
func (h *DBHandler) GetColumns(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	tableName := c.Param("table")
	if tableName == "" {
		h.logger.Error("无效的表名", zap.Error(err))
		response.Error(c, err)
		return
	}

	columns, err := h.dbService.GetColumns(c.Request.Context(), id, tableName)
	if err != nil {
		h.logger.Error("获取列信息失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "read",
		Resource:    "table",
		ResourceID:  id,
		Description: "获取列信息",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, columns)
}

// GetTableData godoc
// @Summary 获取表数据
// @Description 获取指定表的数据，支持分页
// @Tags 数据库操作
// @Produce json
// @Param id path int true "连接ID"
// @Param table path string true "表名"
// @Param page query int false "页码，默认1"
// @Param page_size query int false "每页记录数，默认10"
// @Success 200 {object} entity.QueryResult
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id}/tables/{table}/data [get]
func (h *DBHandler) GetTableData(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	tableName := c.Param("table")
	if tableName == "" {
		h.logger.Error("无效的表名", zap.Error(err))
		response.Error(c, err)
		return
	}

	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))

	result, err := h.dbService.GetTableData(c.Request.Context(), id, tableName, page, pageSize)
	if err != nil {
		h.logger.Error("获取表数据失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "read",
		Resource:    "table",
		ResourceID:  id,
		Description: "获取表数据",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, result)
}

// ExecuteQuery godoc
// @Summary 执行查询
// @Description 执行自定义SQL查询
// @Tags 数据库操作
// @Accept json
// @Produce json
// @Param id path int true "连接ID"
// @Param query body object true "查询信息"
// @Success 200 {object} entity.QueryResult
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Failure 500 {object} errors.Error
// @Router /connections/{id}/query [post]
func (h *DBHandler) ExecuteQuery(c *gin.Context) {
	id, err := strconv.ParseInt(c.Param("id"), 10, 64)
	if err != nil {
		h.logger.Error("无效的连接ID", zap.Error(err))
		response.Error(c, err)
		return
	}

	var req struct {
		Query string `json:"query" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		h.logger.Error("无效的请求参数", zap.Error(err))
		response.Error(c, err)
		return
	}

	result, err := h.dbService.ExecuteQuery(c.Request.Context(), id, req.Query)
	if err != nil {
		h.logger.Error("执行查询失败", zap.Error(err))
		response.Error(c, err)
		return
	}

	// 记录审计日志
	auditLog := &entity.AuditLog{
		UserID:      c.GetInt64("user_id"),
		Action:      "execute",
		Resource:    "query",
		ResourceID:  id,
		Description: "执行SQL查询",
		IP:          c.ClientIP(),
		UserAgent:   c.GetHeader("User-Agent"),
		Status:      "success",
	}
	h.auditRepo.Create(c.Request.Context(), auditLog)

	response.Success(c, result)
}
